package com.shopnight.utils;

import java.util.*;

public class PostRecommendation {
    // 定义帖子类
    static class Post {
        int id; // 帖子ID
        String title; // 帖子标题
        List<String> tags; // 帖子标签
        int likes; // 帖子点赞数
        int comments; // 帖子评论数
        Date createTime; // 帖子创建时间

        public Post(int id, String title, List<String> tags, int likes, int comments, Date createTime) {
            this.id = id;
            this.title = title;
            this.tags = tags;
            this.likes = likes;
            this.comments = comments;
            this.createTime = createTime;
        }
    }

    // 定义TF-IDF值类
    static class TFIDF {
        String word; // 词语
        double tfidf; // TF-IDF值

        public TFIDF(String word, double tfidf) {
            this.word = word;
            this.tfidf = tfidf;
        }
    }

    // 定义相似度值类
    static class Similarity {
        int postId; // 帖子ID
        double similarity; // 相似度值

        public Similarity(int postId, double similarity) {
            this.postId = postId;
            this.similarity = similarity;
        }
    }

    // 计算TF-IDF值
    public static List<TFIDF> calculateTFIDF(List<Post> posts) {
        Map<String, Integer> wordCountMap = new HashMap<>(); // 统计每个词在所有帖子中出现的次数
        Map<Integer, Map<String, Integer>> postWordCountMap = new HashMap<>(); // 统计每个帖子中每个词出现的次数
        int totalPostCount = posts.size(); // 所有帖子的总数

        // 遍历所有帖子，统计每个词在所有帖子中出现的次数和每个帖子中每个词出现的次数
        for (Post post : posts) {
            List<String> words = Arrays.asList(post.title.split(" ")); // 将帖子标题分词
            for (String word : words) {
                // 统计每个词在所有帖子中出现的次数
                wordCountMap.put(word, wordCountMap.getOrDefault(word,0) + 1);
                // 统计每个帖子中每个词出现的次数
                if (!postWordCountMap.containsKey(post.id)) {
                    postWordCountMap.put(post.id, new HashMap<>());
                }
                postWordCountMap.get(post.id).put(word, postWordCountMap.get(post.id).getOrDefault(word, 0) + 1);
            }
        }

        // 计算TF-IDF值
        List<TFIDF> tfidfList = new ArrayList<>();
        for (Post post : posts) {
            List<String> words = Arrays.asList(post.title.split(" ")); // 将帖子标题分词
            for (String word : words) {
                double tf = (double) postWordCountMap.get(post.id).get(word) / words.size(); // 计算词语在帖子中的TF值
                double idf = Math.log((double) totalPostCount / wordCountMap.get(word)); // 计算词语的IDF值
                double tfidf = tf * idf; // 计算词语的TF-IDF值
                tfidfList.add(new TFIDF(word, tfidf));
            }
        }

        return tfidfList;
    }

    // 计算余弦相似度
    public static double calculateCosineSimilarity(List<TFIDF> tfidf1, List<TFIDF> tfidf2) {
        // 将两个帖子的TF-IDF值转化为向量
        Map<String, Double> vector1 = new HashMap<>();
        Map<String, Double> vector2 = new HashMap<>();
        for (TFIDF tfidf : tfidf1) {
            vector1.put(tfidf.word, tfidf.tfidf);
        }
        for (TFIDF tfidf : tfidf2) {
            vector2.put(tfidf.word, tfidf.tfidf);
        }

        // 计算余弦相似度
        double numerator = 0.0;
        double denominator1 = 0.0;
        double denominator2 = 0.0;
        for (String word : vector1.keySet()) {
            if (vector2.containsKey(word)) {
                numerator += vector1.get(word) * vector2.get(word);
            }
            denominator1 += Math.pow(vector1.get(word), 2);
        }
        for (String word : vector2.keySet()) {
            denominator2 += Math.pow(vector2.get(word), 2);
        }
        double denominator = Math.sqrt(denominator1) * Math.sqrt(denominator2);
        if (denominator == 0.0) {
            return 0.0;
        } else {
            return numerator / denominator;
        }
    }

    // 推荐
    public static List<Post> recommend(List<Post> posts, List<Post> viewedPosts) {
        List<TFIDF> viewedTFIDF = calculateTFIDF(viewedPosts); // 计算用户浏览过的帖子的TF-IDF值
        List<Similarity> similarityList = new ArrayList<>(); // 保存与用户浏览过的帖子相似度较高的帖子

        // 遍历所有帖子，计算其与用户浏览过的帖子的相似度
        for (Post post : posts) {
            if (!viewedPosts.contains(post)) {
                List<TFIDF> postTFIDF = calculateTFIDF(Collections.singletonList(post)); // 计算当前帖子的TF-IDF值
                double similarity = calculateCosineSimilarity(viewedTFIDF, postTFIDF); // 计算当前帖子与用户浏览过的帖子的相似度
                similarityList.add(new Similarity(post.id, similarity));
            }
        }

        // 将相似度列表按照相似度值从高到低排序
        Collections.sort(similarityList, (s1, s2) -> Double.compare(s2.similarity, s1.similarity));

        // 根据推荐算法的综合考虑因素（热度、时效性、历史浏览等），返回推荐列表
        List<Post> recommendedPosts = new ArrayList<>();
        for (Similarity similarity : similarityList) {
            for (Post post : posts) {
                if (post.id == similarity.postId) {
                    if (!viewedPosts.contains(post)) { // 推荐列表中不包含用户已经浏览过的帖子
                        if (post.likes >= 10 && post.comments >= 2) { // 热度因素：点赞数大于等于10且评论数大于等于2
                            Date now = new Date();
                            long createTimeDiff = now.getTime() - post.createTime.getTime(); // 计算当前时间与帖子创建时间的时间差
                            long createTimeDiffInDays = createTimeDiff / (1000 * 60 * 60 * 24); // 将时间差转化为天数
                            if (createTimeDiffInDays <= 7) { // 时效性因素：帖子创建时间在一周内
                                recommendedPosts.add(post);
                            }
                        }
                    }
                    break;
                }
            }
        }

        return recommendedPosts;
    }
}